package self.wargon.springcloudstu.servicea.service.impl;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.github.resilience4j.retry.annotation.Retry;
import io.github.resilience4j.timelimiter.annotation.TimeLimiter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import self.wargon.springcloudstu.common.bo.UserInfo;
import self.wargon.springcloudstu.servicea.client.UserServiceClient;
import self.wargon.springcloudstu.servicea.service.TestService;

import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    UserServiceClient userServiceClient;

    @RateLimiter(name = "getUserInfo", fallbackMethod = "rateLimitFallback")
//    @CircuitBreaker(name = "getUserInfo", fallbackMethod = "getUserInfoFallback")
//    @Retry(name = "getUserInfo", fallbackMethod = "getUserInfoFallback")
    @Override
    public UserInfo getUserInfo(String username) {
        log.info("### getUserInfo ###");
        return userServiceClient.getUserInfo(username).getData();
    }

    public UserInfo getUserInfoFallback(String username, Throwable throwable) {
        log.info("### getUserInfoFallback ###");
        log.error("### getUserInfoFallback error: {} ###", throwable.getMessage());
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername(username);
        userInfo.setAlias("Default");
        return userInfo;
    }

    public UserInfo rateLimitFallback(String username, RequestNotPermitted rnp) {
        log.info("### rateLimitFallback ###");
        log.error("### rateLimitFallback error: {} ###", rnp.getMessage());
        throw new RuntimeException("Rate Limit");
    }

    @TimeLimiter(name = "asyncGetUserInfo", fallbackMethod = "asyncGetUserInfoFallback")
    @Override
    public CompletableFuture<UserInfo> asyncGetUserInfo(String username) {
        try {
            Thread.sleep(2100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return userServiceClient.getUserInfo(username).getData();
        });
    }

    public CompletableFuture<UserInfo> asyncGetUserInfoFallback(String username, Throwable ex) {
        throw new RuntimeException("Async TimeLimit");
    }
}
